﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace YXCard
{
    public class ThreadService
    {
        public ThreadService()
        {
        }

        private int m_ThreadCount = 0;
        private int m_ObjectCount = 0;
        private ThreadFunction m_ThreadFunction = null;
        private ThreadFinish m_ThreadFinish = null;
        private Form m_Form = null;
        private Thread[] m_Threads = null;

        public void Start(Form form, ThreadFunction tfun, ThreadFinish ffun, int count, int maxthread)
        {
            if (count == 0 || maxthread == 0)
            {
                ffun.Invoke();
                return;
            }

            m_Form = form;
            m_ThreadFunction = tfun;
            m_ThreadFinish = ffun;
            m_ObjectCount = count;

            m_ThreadCount = maxthread;

            ThreadRun = true;
            m_CurrIndex = 0;

            m_Threads = new Thread[m_ThreadCount];

            for (int i = 0; i < m_ThreadCount; ++i)
            {
                m_Threads[i] = new Thread(DoThread);
                m_Threads[i].SetApartmentState(ApartmentState.STA);
            }

            int tnum = m_ThreadCount;
            for (int i = 0; i < tnum; ++i)
            {
                m_Threads[i].Start(i);
            }
        }

        bool ThreadRun = false;
        public bool Run
        {
            get
            {
                return ThreadRun;
            }
        }

        private void DoThread(object obj)
        {
            int threadnum = (int)obj;

            if (ThreadRun)
            {
                int index = getIndex();
                if (index >= 0)
                {
                    m_ThreadFunction.Invoke(threadnum, index);

                    DoThread(threadnum);

                    return;
                }
            }
            ThreadDone();
        }


        object ThreadDoneObj = new object();
        private void ThreadDone()
        {
            lock (ThreadDoneObj)
            {
                try
                {
                    --m_ThreadCount;

                    if (m_ThreadCount <= 0)
                    {
                        m_Threads = null;
                        m_Form.BeginInvoke(m_ThreadFinish);
                    }
                }
                catch (Exception)
                {
                }
            }
        }

        private object IndexDoneObj = new object();
        private int m_CurrIndex = 0;
        private int getIndex()
        {
            lock (IndexDoneObj)
            {
                if (m_CurrIndex < m_ObjectCount)
                {
                    return m_CurrIndex++;
                }
                else
                {
                    return -1;
                }
            }
        }

        public void Stop()
        {
            ThreadRun = false;
        }

        public IAsyncResult FormInvoke(FormInvokeFunc func)
        {
            return m_Form.BeginInvoke(func, null);
        }
    }

    public delegate void ThreadFunction(int thread, int index);
    public delegate void ThreadFinish();
    public delegate void FormInvokeFunc();
}
